import { Client as SSHClient } from 'ssh2';
import fs from 'fs';
import path from 'path';

export class SimpleSSH {
  constructor(options) {
    this.options = options;
    this.client = new SSHClient();
    this.isReady = false;
  }

  connect() {
    return new Promise((resolve, reject) => {
      this.client
        .on('ready', () => {
          this.isReady = true;
          resolve(true);
        })
        .on('error', (err) => {
          reject(err);
        })
        .on('end', () => {
          this.isReady = false;
        })
        .on('close', () => {
          this.isReady = false;
        })
        .connect(this.options);
    });
  }

  end() {
    try {
      this.client.end();
    } catch {}
  }

  exec(command) {
    return new Promise((resolve, reject) => {
      this.client.exec(command, (err, stream) => {
        if (err) return reject(err);
        let stdout = '';
        let stderr = '';
        stream
          .on('close', (code, signal) => {
            if (code === 0) resolve({ code, stdout, stderr });
            else reject(new Error(stderr || `Command exited with code ${code}`));
          })
          .on('data', (data) => {
            stdout += data.toString();
          })
          .stderr.on('data', (data) => {
            stderr += data.toString();
          });
      });
    });
  }

  async ensureRemoteDir(remoteDir) {
    const escaped = remoteDir.replace(/"/g, '\\"');
    await this.exec(`mkdir -p "${escaped}"`);
  }

  async uploadFile(localFile, remoteFile) {
    const remoteDir = path.posix.dirname(remoteFile.replace(/\\/g, '/'));
    await this.ensureRemoteDir(remoteDir);
    const content = fs.readFileSync(localFile);
    // 使用 base64 通过 stdin 写入，避免转义问题
    const b64 = content.toString('base64');
    const escapedTarget = remoteFile.replace(/\\/g, '/').replace(/"/g, '\\"');
    const cmd = `base64 -d > "${escapedTarget}"`;
    return new Promise((resolve, reject) => {
      this.client.exec(cmd, (err, stream) => {
        if (err) return reject(err);
        stream.on('close', (code) => {
          if (code === 0) resolve();
          else reject(new Error(`upload failed with code ${code}`));
        });
        stream.stdin.end(b64);
      });
    });
  }

  async removeFile(remoteFile) {
    const escaped = remoteFile.replace(/\\/g, '/').replace(/"/g, '\\"');
    await this.exec(`rm -f "${escaped}"`);
  }

  async removeDir(remoteDir) {
    const escaped = remoteDir.replace(/\\/g, '/').replace(/"/g, '\\"');
    await this.exec(`rm -rf "${escaped}"`);
  }
}

export default SimpleSSH;


